package metadata

import (
	"cloud-entropy-storage-system/server/model"
	"github.com/asdine/storm/v3"
	"github.com/asdine/storm/v3/q"
	"sync"
)

type MetaData struct {
	db   *storm.DB
	lock sync.Mutex
}

func NewMetaData(db *storm.DB) *MetaData {
	if err := db.Init(&MetaDetail{}); err != nil {
		return nil
	}
	return &MetaData{db: db}
}

func (m *MetaData) ImgCount() (int, error) {
	var num int
	num, err := m.db.Select(q.And(q.Eq("IsImg", 1), q.Eq("Flag", model.FlagInit))).Count(&MetaDetail{})
	return num, err

}

func (m *MetaData) ImgList(pageNum, limit int, dir string) ([]MetaDetail, error) {
	offset := (pageNum - 1) * limit
	var (
		ds    []MetaDetail
		query q.Matcher
	)
	if dir == "" {
		query = q.And(q.Eq("IsImg", 1), q.Eq("Flag", model.FlagInit))
	} else {
		query = q.And(q.Re("FilePath", dir), q.Eq("IsImg", 1), q.Eq("Flag", model.FlagInit))
	}
	err := m.db.Select(query).Limit(limit).Skip(offset).Reverse().Find(&ds)
	if err != nil {
		if err == storm.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return ds, nil
}

func (m *MetaData) List(pageNum, limit int) ([]MetaDetail, error) {
	offset := (pageNum - 1) * limit
	var ds []MetaDetail
	err := m.db.Select(q.Eq("Flag", model.FlagInit)).Limit(limit).Skip(offset).Reverse().Find(&ds)
	if err != nil {
		if err == storm.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return ds, nil
}

func (m *MetaData) Get(filePath string) (*MetaDetail, error) {
	var detail MetaDetail
	err := m.db.One("FilePath", filePath, &detail)
	if err != nil {
		if err == storm.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return &detail, nil
}

func (m *MetaData) Set(detail *MetaDetail) error {
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.db.Save(detail)
}

func (m *MetaData) Delete(id int) error {
	m.lock.Lock()
	defer m.lock.Unlock()
	return m.db.UpdateField(&MetaDetail{ID: id}, "Flag", model.FlagDelete)
}

func (m *MetaData) Has(filePath string) bool {
	var detail MetaDetail
	err := m.db.One("FilePath", filePath, &detail)
	if err != nil {
		if err == storm.ErrNotFound {
			return false
		}
		return false
	}
	return true
}

func (m *MetaData) HasMD(md string) bool {
	var detail MetaDetail
	err := m.db.One("Md", md, &detail)
	if err != nil {
		if err == storm.ErrNotFound {
			return false
		}
		return false
	}
	return true
}

func (m *MetaData) GetMD(md string) (*MetaDetail, error) {
	var detail MetaDetail
	err := m.db.One("Md", md, &detail)
	if err != nil {
		if err == storm.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}

	return &detail, nil
}

func (m *MetaData) Count() (int, error) {
	return m.db.Count(&MetaDetail{})
}
